package cn.edu.nju.ws.sview.reasoning.magicsets;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import cn.edu.nju.ws.sview.rdf.Resource;
import cn.edu.nju.ws.sview.rdf.ResourceFactory;
import cn.edu.nju.ws.sview.reasoning.Atom;
import cn.edu.nju.ws.sview.reasoning.Constant;
import cn.edu.nju.ws.sview.reasoning.GroundAtom;
import cn.edu.nju.ws.sview.reasoning.Predicate;
import cn.edu.nju.ws.sview.reasoning.ProductionMemory;
import cn.edu.nju.ws.sview.reasoning.Rule;
import cn.edu.nju.ws.sview.reasoning.Term;
import cn.edu.nju.ws.sview.reasoning.Variable;
import cn.edu.nju.ws.sview.reasoning.provenance.ProvenanceFactory;

/**
 * @author Gong Saisai
 * Supplementary magic sets
 * 
 */
public class MagicTemplates {
    private  Atom<Term> query;
    private  ArrayList<Rule> originalRules;
    private ArrayList<Rule> rewrittenRules;
    private ArrayList<GroundAtom> seed;
    private HashMap<PredArity,Resource> map =null;
    private HashMap<Integer,HashMap<Integer,Atom<Term>>> supmap = null;
    public MagicTemplates(Atom<Term> query, ArrayList<Rule> originalRules){
   	 this.query  = query;
   	 this.originalRules = originalRules;
   	 this.rewrittenRules = new ArrayList<Rule>();
   	 this.map = new HashMap<PredArity,Resource>();
   	 this.supmap = new HashMap<Integer,HashMap<Integer,Atom<Term>>>();
   	 this.seed = new ArrayList<GroundAtom>();
    }
    /**
     * <p>
     * If the query has no ground bindings ,return.
     * </p>
     * @throws SQLException 
     */
    public void  rewriting() throws SQLException{
   	 if(this.query==null)
   		 throw new NullPointerException("The argument");
   	 ArrayList<Integer> boundPosition = this.query.getPattern().getConstIndices();
   	 int i;
   	 HashMap<Predicate,ArrayList<Rule>> pred2rule = new HashMap<Predicate,ArrayList<Rule>>();
   	 for(i=0;i<this.originalRules.size();i++){
   		 Predicate pred = originalRules.get(i).getHead().getPredicate() ;
   		 if(!pred2rule.containsKey(pred)){
   			 ArrayList<Rule> list= new ArrayList<Rule>();
   			 pred2rule.put(pred, list) ;
   		 }
   		 pred2rule.get(pred).add(originalRules.get(i)) ;
   	 }
   	 Predicate queryPred = this.query.getPredicate();
   	 ArrayList<Constant> seedBoundArg = this.query.getPattern().getConstTerms();
   	 if (seedBoundArg.size() > 0) {
			BoundFree[] adornment = new BoundFree[queryPred.getArity()];
			for (i = 0; i < queryPred.getArity(); i++) {
				if (boundPosition.contains(i)) {
					adornment[i] = BoundFree.BOUND;
				} else
					adornment[i] = BoundFree.FREE;
			}
			MagicPredicate seedPred = this.makeMagicPredicate(queryPred
					.getResource(), boundPosition.size(), adornment);
			ArrayList<Constant> seedBoundTerms = new ArrayList<Constant>();
			for (i = 0; i < seedBoundArg.size(); i++) {
				seedBoundTerms.add((Constant) seedBoundArg.get(i));
			}
			//remove the adornedment
			GroundAtom mySeedFact = new GroundAtom(((AdornedPredicate)seedPred).getPred(),
					seedBoundTerms, ProvenanceFactory.getInstance()
							.createProvFromTemporary());
			this.setSeed(mySeedFact);
	 }
   	 AdornedPredicate adornedQueryPred =MagicSetsFactory.getInstance().createAdornedPredicate(this.query.getPredicate(), boundPosition) ;
   	 ArrayList<Rule> adornedProg = adornedProgram(pred2rule,adornedQueryPred);
   	 //generate supplementary magic rules,and the correspond rule number of supplementary magic predicate
   	 //is recorded
   	 ArrayList<Rule> supmagicRules  = genSupmagicRules(adornedProg);
   	 //we sepreate magic rules and adorned rules
   	 ArrayList<Rule> magicRules = genMagicRules(adornedProg) ;
   	 ArrayList<Rule> modifiedRules =  modifyRules(adornedProg) ;
   	 ArrayList<Rule> unadornedRules = unadornedRules(modifiedRules,magicRules,supmagicRules) ;
   	 ArrayList<Rule> ruleList = reorder(unadornedRules,this.query);
   	 this.rewrittenRules.addAll(ruleList) ;
   	 ruleList.clear();
   	 ruleList = null;
    }
    
    /**
     * <p>
     *    adorned program rewritting
     * </p>
     * @param pred2rule. pred vs rule mapping
     * @param adornedQueryPred. query adorned predicate
     * @return the adorned program
     */
    private ArrayList<Rule> adornedProgram(HashMap<Predicate,ArrayList<Rule>> pred2rule,AdornedPredicate adornedQueryPred){
   	 // store all the intensional preds
		HashSet<Predicate> intensionalPreds = new HashSet<Predicate>();
		intensionalPreds.addAll(pred2rule.keySet());
		ArrayList<Rule> adornedProg = new ArrayList<Rule>();
		HashSet<AdornedPredicate> todoList = new HashSet<AdornedPredicate>();
		HashSet<AdornedPredicate> allAdornedPreds = new HashSet<AdornedPredicate>();
		todoList.add(adornedQueryPred);
		allAdornedPreds.add(adornedQueryPred);
		while (todoList.size() > 0) {
			AdornedPredicate adornedPred = todoList.iterator().next();
			todoList.remove(adornedPred);
			ArrayList<Rule> rules = pred2rule.get(adornedPred.getPred());
			if (rules != null) {
				for (Rule rule : rules) {
					ArrayList<AdornedPredicate> newAdornedPreds = adornedRule(
							adornedProg, rule, adornedPred, intensionalPreds);
					for (AdornedPredicate adPred : newAdornedPreds) {
						if (!allAdornedPreds.contains(adPred)) {
							allAdornedPreds.add(adPred);
							todoList.add(adPred);
						}
					}
				}
			}
		}
		return adornedProg;
    }

	/**
	 * <p>
	 * generate adorned rules 
	 * </p>
	 * <p>
	 * for the extensional predicates and these predicates not in sip,we do not
	 * generate an adorned predicate
	 * </p>
	 * 
	 * @param adornedProg.
	 * @param rule.
	 * @param adornedPred
	 *            . The adorned head predicate
	 * @param intensionalPreds
	 *            the set of intensional predicates
	 * @return
	 */
    private ArrayList<AdornedPredicate> adornedRule(ArrayList<Rule> adornedProg,Rule rule,AdornedPredicate adornedPred,HashSet<Predicate> intensionalPreds){
   	    ArrayList<AdornedPredicate> list = new ArrayList<AdornedPredicate>();
	    Atom<Term> headAtom = rule.getHead();
		ArrayList<Term> queryBoundArgs = this.getBoundArgs(adornedPred,
				headAtom);
		ArrayList<Atom<Term>> adornedBodyLiterals = new ArrayList<Atom<Term>>();
		ArrayList<Atom<Term>> bodyLiterals = rule.getBody();
		HashMap<Variable, ArrayList<Integer>> var2Atom = new HashMap<Variable, ArrayList<Integer>>();
		for (int i = 0; i < bodyLiterals.size(); i++) {
			HashSet<Variable> set = (HashSet<Variable>) bodyLiterals.get(i)
					.getVariables();
			for (Variable mVar : set) {
				if (!var2Atom.containsKey(mVar))
					var2Atom.put(mVar, new ArrayList<Integer>());
				var2Atom.get(mVar).add(i);
			}
		}
		HashSet<Integer> visited = new HashSet<Integer>();
		ArrayList<Term> todoList = new ArrayList<Term>();
		HashSet<Term> boundVariables = new HashSet<Term>();
		for (Term term : queryBoundArgs) {
			// may be a constant in the orginal predicate
			if (term instanceof Variable) {
				if (!boundVariables.contains(term)) {
					boundVariables.add(term);
					todoList.add(term);
				}
			}
		}
		int count = 0;
		while (count<bodyLiterals.size()) {
			//if bounded variable exist sort and add all the related atoms
			if (todoList.size() > 0) {
				Term boundVar = todoList.remove(0);
				if (!(boundVar instanceof Variable))
					throw new IllegalArgumentException(
							"The argument must be a variable");
				ArrayList<Integer> nextAtoms = var2Atom
						.get((Variable) boundVar);
				for (Integer mInt : nextAtoms) {
					if (!visited.contains(mInt)) {
						visited.add(mInt);
						Atom<Term> nextAtom = bodyLiterals.get(mInt);
						if (intensionalPreds.contains(nextAtom.getPredicate())) {
							/***
							 * bound by original variables excluding the
							 * constant in the literal
							 ***/
							ArrayList<Integer> constIndex = this.genAdornment(
									nextAtom, boundVariables);
							AdornedPredicate mAdornedPred = MagicSetsFactory
									.getInstance()
									.createAdornedPredicate(
											nextAtom.getPredicate(), constIndex);
							Atom<Term> mAtom = new Atom<Term>(mAdornedPred,
									nextAtom.getTerms());
							// add aorened atom
							adornedBodyLiterals.add(mAtom);
							count++;
							list.add(mAdornedPred);
						} else {
							adornedBodyLiterals.add(nextAtom);
							count++;
						}
						// bring in the variables of the new literals
						Set<Variable> newVariables = nextAtom.getVariables();
						for (Variable _var : newVariables) {
							if (!boundVariables.contains(_var)) {
								boundVariables.add(_var);
								todoList.add(_var);
							}
						}
					}
				}
			}else{
				//add a body atom and bring in bounded variables
				for (int i = 0; i < bodyLiterals.size(); i++) {
					
				if (!visited.contains(i)) {
					visited.add(i);
					Atom<Term> _atom = bodyLiterals.get(i);
					if (intensionalPreds.contains(_atom.getPredicate())) {
						ArrayList<Integer> constIndex =  this.genAdornment(_atom, boundVariables);
						AdornedPredicate mAdornedPred = MagicSetsFactory
								.getInstance().createAdornedPredicate(
										_atom.getPredicate(), constIndex);
						Atom<Term> mAtom = new Atom<Term>(mAdornedPred,_atom.getTerms()) ;
						list.add(mAdornedPred);
						adornedBodyLiterals.add(mAtom);
						count++;
					}else{
						adornedBodyLiterals.add(_atom);
						count++;
					}
					// bring in the variables of the new literals
					Set<Variable> newVariables = _atom.getVariables();
					for (Variable _var : newVariables) {
						if (!boundVariables.contains(_var)) {
							boundVariables.add(_var);
							todoList.add(_var);
						}
					}
					break;
				}
				
			}
			}
		}
		
		Atom<Term> adornedHeadAtom = new Atom<Term>(adornedPred, headAtom
				.getTerms());
		Rule nextRule = new Rule(adornedHeadAtom, adornedBodyLiterals, rule
				.getProvenance());
		adornedProg.add(nextRule);
		return list;
    }
    
    private ArrayList<Rule> genSupmagicRules(ArrayList<Rule> adornedProg) throws SQLException{
    	ArrayList<Rule> supmagicRules = new ArrayList<Rule>();
		for (int i = 0; i < adornedProg.size(); i++) {
			Rule r = adornedProg.get(i);
			if (!(r.getHead().getPredicate() instanceof AdornedPredicate))
				continue;
			AdornedPredicate headPred = (AdornedPredicate)r.getHead().getPredicate();
			ArrayList<Atom<Term>> bodyLiterals = r.getBody();
			HashSet<Term> variables = new HashSet<Term>();
			variables.addAll(r.getHead().getVariables());
			//supmagic predicate
			ArrayList<Integer> array = new ArrayList<Integer>();
			for (int j = 1; j < bodyLiterals.size(); j++) {
				Atom<Term> mAtom = bodyLiterals.get(j);
				Predicate predicate = mAtom.getPredicate();
				if (predicate instanceof AdornedPredicate) {
					Atom<Term> atom = null;
					int pos = 0;
					if (array.size() == 0) {
						pos = 0;
						if (headPred.getBoundArgNum() > 0) {
							MagicPredicate magicFirstPred = this
									.makeMagicPredicate(headPred.getResource(),
											headPred.getBoundArgNum(),
											headPred.getAdornment());
							ArrayList<Term> _magicfirstTerms = this
									.getBoundArgs(headPred, r.getHead());
							atom = new Atom<Term>(magicFirstPred,
									_magicfirstTerms);
						}
					} else {
						pos = array.get(array.size() - 1);
						atom = this.getSupmagicAtom(i, pos);
					}
					ArrayList<Term> mterms = new ArrayList<Term>();
					if(atom!=null)
						mterms.addAll(atom.getTerms());
					ArrayList<Atom<Term>> body = new ArrayList<Atom<Term>>();
					if (atom != null)
						body.add(atom);
					for (int k = pos; k < j; k++) {
						Atom<Term> literal = bodyLiterals.get(k);
						body.add(literal);
						for (Term term : this.getVariables(literal.getTerms())) {
							if (!mterms.contains(term))
								mterms.add(term);
						}
					}
                    if(body.size()>0){
						HashSet<Term> remain = new HashSet<Term>();
						for (int m = j; m < bodyLiterals.size(); m++) {
							remain.addAll(this.getVariables(bodyLiterals.get(m)
									.getTerms()));
						}
						remain.addAll(variables);
						ArrayList<Term> headTerms = new ArrayList<Term>();
						for (Term headTerm : mterms) {
							if (remain.contains(headTerm)) {
								headTerms.add(headTerm);
							}
						}
						Atom<Term> headAtom = this.makeSupmagicAtom(i, j,
								headTerms);
						array.add(j) ;
						Rule supmagicRule = new Rule(headAtom, body,
								ProvenanceFactory.getInstance()
										.createProvFromTemporary());
						supmagicRules.add(supmagicRule);
                    }
				}
			}
		}
		return supmagicRules;
    }
    
   /**
    * generate magic rules
    * @param adornedProg
    * @return
 * @throws SQLException 
    */
    private ArrayList<Rule> genMagicRules(ArrayList<Rule> adornedProg) throws SQLException{
    	ArrayList<Rule> magicRules = new ArrayList<Rule>();
		for (int i = 0; i < adornedProg.size(); i++) {
			Rule r = adornedProg.get(i);
			if (!(r.getHead().getPredicate() instanceof AdornedPredicate))
				continue;
			AdornedPredicate headPred = (AdornedPredicate)r.getHead().getPredicate();
			ArrayList<Atom<Term>> bodyLiterals = r.getBody();
			for (int j = 0; j < bodyLiterals.size(); j++) {
				Atom<Term> mAtom = bodyLiterals.get(j);
				Predicate predicate = mAtom.getPredicate();
				if (predicate instanceof AdornedPredicate) {
					AdornedPredicate mAdornedPredicate = (AdornedPredicate) predicate;
					if (mAdornedPredicate.getBoundArgNum() == 0)
						continue;
					else {
						ArrayList<Integer> boundPosition = mAtom.getPattern()
								.getConstIndices();
						// only the case for the form of p^bf('a',x)
						if (boundPosition.size() == mAdornedPredicate
								.getBoundArgNum()) {
							ArrayList<Constant> seedBoundArg = mAtom.getPattern()
									.getConstTerms();
							MagicPredicate seedPred = this.makeMagicPredicate(
									predicate.getResource(), mAdornedPredicate
											.getBoundArgNum(),
									mAdornedPredicate.getAdornment());
							ArrayList<Constant> BoundTerms = new ArrayList<Constant>();
							for (int k = 0; k < seedBoundArg.size(); k++) {
								BoundTerms.add((Constant) seedBoundArg.get(k));
							}
							GroundAtom mySeed = new GroundAtom(((AdornedPredicate)seedPred).getPred(),
									BoundTerms, ProvenanceFactory.getInstance()
											.createProvFromTemporary());
							this.setSeed(mySeed);
						} else {
							// Be careful. Here the second argument equals the
							// number of
							// bound arguments of adornedPredicate.
							MagicPredicate magicPred = this.makeMagicPredicate(
									predicate.getResource(),
									((AdornedPredicate) predicate)
											.getBoundArgNum(),
									((AdornedPredicate) predicate)
											.getAdornment());
							ArrayList<Term> terms = this.getBoundArgs(
									magicPred, mAtom);
							Atom<Term> headAtom = new Atom<Term>(magicPred,
									terms);
							ArrayList<Atom<Term>> magicBodyLiterals = new ArrayList<Atom<Term>>();
                            Atom<Term> supatom = this.getSupmagicAtom(i, j);
                            if(supatom!=null){
                            	magicBodyLiterals.add(supatom);	
                            }else{
                            	//it must be at the first atom of the body
        						if (headPred.getBoundArgNum() > 0) {
        							MagicPredicate magicFirstPred = this
        									.makeMagicPredicate(headPred.getResource(),
        											headPred.getBoundArgNum(),
        											headPred.getAdornment());
        							ArrayList<Term> _magicfirstTerms = this
        									.getBoundArgs(headPred, r.getHead());
        							Atom<Term> atom = new Atom<Term>(magicFirstPred,
        									_magicfirstTerms);
        							magicBodyLiterals.add(atom);
        						}
                            }
							Rule nextMagicRule = new Rule(headAtom,
									magicBodyLiterals, ProvenanceFactory
											.getInstance()
											.createProvFromTemporary());
							magicRules.add(nextMagicRule);
						}
					}
				}
			}
		}
		return magicRules;
    }
    
    private MagicPredicate makeMagicPredicate(Resource SRCResource, int arity,BoundFree[] adornment) throws SQLException{
    	PredArity predArity = new PredArity(SRCResource,arity);
    	Resource resource = null;
    	if(!map.containsKey(predArity)){
    		map.put(predArity, ResourceFactory.getInstance().createTemporaryRDFResource(SRCResource)) ;
    	}
    	resource = map.get(predArity) ;
    	MagicPredicate mp = MagicSetsFactory.getInstance().createMagicPredicate(resource, arity, adornment);
    	return mp;
    }
    
    private Atom<Term> makeSupmagicAtom(int ruleId,int literalPos,ArrayList<Term> terms){
    	Atom<Term> atom = null;
    	if(!supmap.containsKey(ruleId)){
    		supmap.put(ruleId, new HashMap<Integer,Atom<Term>>()) ;
    	}
    	HashMap<Integer,Atom<Term>> m_map = supmap.get(ruleId) ;
    	if(!m_map.containsKey(literalPos)){
    		Predicate pred = new Predicate(ResourceFactory.getInstance().createSupmagicResource(ruleId,literalPos),
    				terms.size());
    		atom = new Atom<Term>(pred,terms);
    		m_map.put(literalPos, atom) ;
    	}else{
    		atom = m_map.get(literalPos) ;
    	}
        return  atom;
    }
    
    private Atom<Term> getSupmagicAtom(int ruleId,int literalPos){
    	if(supmap.containsKey(ruleId)){
    		HashMap<Integer,Atom<Term>> mmap = supmap.get(ruleId) ;
    		if(mmap.containsKey(literalPos))
    			return mmap.get(literalPos) ;
    	}
    	return null;
    }
    
   /**
	 * rule body modification of origin rules 
	 * 
	 * @param adornedProg
	 * @return
	 * @throws SQLException
	 */
	private ArrayList<Rule> modifyRules(ArrayList<Rule> adornedProg)
			throws SQLException {
		ArrayList<Rule> array = new ArrayList<Rule>();
		for (int i = 0; i < adornedProg.size(); i++) {
			Rule r = adornedProg.get(i);
			if (!(r.getHead().getPredicate() instanceof AdornedPredicate)) {
				array.add(r);
				continue;
			}
			ArrayList<Atom<Term>> nextBody = new ArrayList<Atom<Term>>();
			ArrayList<Atom<Term>> bodyLiterals = r.getBody();
			ArrayList<Term> _magicfirstTerms = this.getBoundArgs(
					(AdornedPredicate) r.getHead().getPredicate(), r.getHead());
			AdornedPredicate predicate = (AdornedPredicate) r.getHead()
					.getPredicate();
			int pos = -1;
			for(int j=bodyLiterals.size()-1;j>=0;j--){
				Predicate pred = bodyLiterals.get(j).getPredicate();
				if(pred instanceof AdornedPredicate){
					pos = j;
					break;
				}
			}
			if(pos<=0){
				if (predicate.getBoundArgNum() > 0) {
					MagicPredicate magicFirstPred = this.makeMagicPredicate(
							predicate.getResource(),
							predicate.getBoundArgNum(),
							predicate.getAdornment());
					Atom<Term> _magicfirstAtom = new Atom<Term>(magicFirstPred,
							_magicfirstTerms);
					nextBody.add(_magicfirstAtom);
				}
				nextBody.addAll(bodyLiterals);
			}else{
				Atom<Term> atom  = this.getSupmagicAtom(i, pos) ;
				if(atom!=null){
					nextBody.add(atom) ;
				}
				for(int k=pos;k<bodyLiterals.size();k++)
					nextBody.add(bodyLiterals.get(k)) ;
			}
			Rule nextRule = new Rule(r.getHead(), nextBody, r.getProvenance());
			array.add(nextRule);
		}
		return array;
	}

	/**
	 *generate adorned rules 
	 * 
	 * @param adornedProg
	 * @param magicRules
	 * @return
	 */
	private ArrayList<Rule> unadornedRules(ArrayList<Rule> adornedProg,
			ArrayList<Rule> magicRules,ArrayList<Rule> supmagicRules) {
		ArrayList<Rule> list = new ArrayList<Rule>();
		for (Rule rule : adornedProg) {
			ArrayList<Atom<Term>> bodylist = new ArrayList<Atom<Term>>();
			Atom<Term> headAtom = unadornedAtom(rule.getHead());
			for (Atom<Term> atom : rule.getBody()) {
				bodylist.add(unadornedAtom(atom));
			}
			Rule mRule = new Rule(headAtom, bodylist, rule.getProvenance());
			list.add(mRule);
		}
		for (Rule rule : magicRules) {
			ArrayList<Atom<Term>> bodylist = new ArrayList<Atom<Term>>();
			Atom<Term> headAtom = unadornedAtom(rule.getHead());
			for (Atom<Term> atom : rule.getBody()) {
				bodylist.add(unadornedAtom(atom));
			}
			Rule mRule = new Rule(headAtom, bodylist, rule.getProvenance());
			list.add(mRule);
		}
		for (Rule rule : supmagicRules) {
			ArrayList<Atom<Term>> bodylist = new ArrayList<Atom<Term>>();
			Atom<Term> headAtom = unadornedAtom(rule.getHead());
			for (Atom<Term> atom : rule.getBody()) {
				bodylist.add(unadornedAtom(atom));
			}
			Rule mRule = new Rule(headAtom, bodylist, rule.getProvenance());
			list.add(mRule);
		}
		return list;
	}
	
    /**
     * rule reorder
     * @param prog. the program
     * @param query. the query
     * @return reordered program
     */
    private ArrayList<Rule> reorder(ArrayList<Rule> prog,Atom<Term> query){
   	 ProductionMemory pm = new ProductionMemory();
   	 for(Rule rule:prog){
   		 pm.addRule(rule) ;
   	 }
   	 return pm.sort(query) ;
    }
    
    public ArrayList<Term> getVariables(ArrayList<Term> terms){
    	ArrayList<Term> result = new ArrayList<Term>();
    	for(int i=0;i<terms.size();i++){
    		if(terms.get(i) instanceof Variable){
    			result.add(terms.get(i)) ;
    		}
    	}
    	return result;
    }
    
    /**
	 * get rewritten rules
	 * @return
     * @throws SQLException 
	 */
	public ArrayList<Rule> getRewrittenRules() throws SQLException {
		return this.rewrittenRules;
	}
    
    /**
	 *  get magicsets seed
	 * 
	 * @return
	 */
	public ArrayList<GroundAtom> getSeed() {
		return this.seed;
	}

	/**
	 *magicsets seed
	 * 
	 * @param seed
	 */
	private void setSeed(GroundAtom seed) {
		this.seed.add(seed);
	}
    
    /**
     * adorned predicate arguments
     * @param pred
     * @param atom
     * @return. 
     */
    private ArrayList<Term> getBoundArgs(AdornedPredicate pred,Atom<Term> atom){
   	    ArrayList<Term> array = new ArrayList<Term>();
		BoundFree[] adornment = pred.getAdornment();
		for (int i = 0; i < adornment.length; i++) {
			if (adornment[i] == BoundFree.BOUND)				
				array.add(atom.get(i));
		}
		return array;
    }
    
    /**
     * SIP Atom adornment
     * @param atom. 
     * @param boundVariables.bound vars of front literals via SIP 
     * @return. Atom bound positions
     */
    private ArrayList<Integer> genAdornment(Atom<Term> atom,HashSet<Term> boundVariables){
   	    ArrayList<Integer> constIndex = new ArrayList<Integer>();
		for (int i = 0; i < atom.size(); i++) {
			Term term = atom.get(i);
	   		 if(term instanceof Constant)
    			 constIndex.add(i);
    		 else if(boundVariables.contains(term)){
    			 constIndex.add(i) ;
    		 }
		}
		return constIndex;
    }
    
    /**
	 * remove atom adornedPredicates' adornment
	 * 
	 * @param atom
	 * @return
	 */
	public Atom<Term> unadornedAtom(Atom<Term> atom) {
		Predicate mPred = atom.getPredicate();
		if (mPred instanceof AdornedPredicate) {
			mPred = ((AdornedPredicate) mPred).getPred();
		}
		return new Atom<Term>(mPred, atom.getTerms());
	}
	
	class PredArity{
	   Resource pred;
	   int arity;
	   public PredArity(Resource pred, int arity){
		   this.pred = pred;
		   this.arity = arity;
	   }
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + arity;
		result = prime * result + ((pred == null) ? 0 : pred.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof PredArity){
			PredArity pa = (PredArity)obj;
			if(pa.arity==this.arity&&this.pred.equals(pa.pred))
				return true;
		}
		return false;
	}
		
	}
}

